// Learn cc.Class:
//  - [Chinese] https://docs.cocos.com/creator/manual/zh/scripting/class.html
//  - [English] http://docs.cocos2d-x.org/creator/manual/en/scripting/class.html
// Learn Attribute:
//  - [Chinese] https://docs.cocos.com/creator/manual/zh/scripting/reference/attributes.html
//  - [English] http://docs.cocos2d-x.org/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - [Chinese] https://docs.cocos.com/creator/manual/zh/scripting/life-cycle-callbacks.html
//  - [English] https://www.cocos2d-x.org/docs/creator/manual/en/scripting/life-cycle-callbacks.html

// game art from : https://openpixelproject.itch.io/opp2017sprites
const MOVE_LEFT = 1;
const MOVE_RIGHT = 2;
const MESSAGE = 0;
const TIP = 1;
const CLICK = 'CLICK'
const SHIFT = 'SHIFT'
const messageBoard = require('MassageBoard')
const LevelPass = require('LevelPass')
const CameraControl = require('CameraControl')
const isMobile = cc.sys.isMobile;

cc.macro.ENABLE_TILEDMAP_CULLING = false;

cc.Class({
    extends: cc.Component,

    properties: {
        lightPlane: {
            type:cc.Node,
            default:null,
            tooltip:'光明位面的节点组'
        },
        darkPlane: {
            type:cc.Node,
            default:null,
            tooltip:'黑暗位面的节点组'
        },
        operationBoard: {
            type: cc.Prefab,
            default: null,
            tooltip:'操作手柄预制体'
        },
        flashPerfab: {
            type: cc.Prefab,
            default: null,
            tooltip:'闪烁预制体'
        },
        onPhone: {
            default: false,
            tooltip: '是否使用手机版配置：使用手柄操作'
        },
        level: {
            default: 1,
            tooltip:'组件所在的关卡，根据不同关卡调用不同设置'
        },
        levelPassPerfab: {
            default: null,
            type:cc.Prefab,
            tooltip:'过关画面预制体'
        },
        messagePerfab:{
            type:cc.Prefab,
            default: null,
            tooltip:'对话框富文本预制'

        },
        tipLabel:{
            type:cc.Prefab,
            default: null,
            tooltip:'提示消息富文本预制'

        },
        ghost:{
            type:cc.Prefab,
            default: null,
            tooltip:'死亡幽灵预制'
        },
        backTip:{
            type:cc.Prefab,
            default: null,
            tooltip:'回到标题预制'
        },
        actorPerfab: {
            default: null,
            type:cc.Prefab,
            tooltip:'主角预制体'
        },
        animParticles: {
            default: [],
            type: [cc.Prefab],
            tooltip:'粒子动效动画'
        },
        tilePrefab: {
            default: [],
            type: [cc.Prefab],
            tooltip:'图块预制体'
        },
        startPosition:{
            default: new cc.Vec2(),
            tooltip:'开始位置'
        },
        levelContent: cc.Node,
        bgm: '',
        debug:false,
        cameraControl:CameraControl
    },

    // use this for initialization
    onLoad: function () {
        // 启用物理
        cc.director.getPhysicsManager().enabled = true;
        // 临时的初始化设置
        if (this.debug) {
            cc.director.getPhysicsManager().debugDrawFlags = cc.PhysicsManager.DrawBits.e_aabbBit |
            cc.PhysicsManager.DrawBits.e_pairBit |
            cc.PhysicsManager.DrawBits.e_centerOfMassBit |
            cc.PhysicsManager.DrawBits.e_jointBit |
            cc.PhysicsManager.DrawBits.e_shapeBit;
        } else {
            cc.director.getPhysicsManager().debugDrawFlags =
            cc.PhysicsManager.DrawBits.e_jointBit;
        };
        this._left = false;
        this._right = false;
        this._up = false;
        this._space = false;
        // 可操作
        this.canOperate = false;
        // 失败标签
        this.gameEnd = false;
        // 事件节点
        this.eventNode = null;
        // 是否有事件运行
        this.onEvent = true;
        // 事件运行步数
        this.eventStep = -1;
        // 事件运行满足条件
        this.onPass = false;
        // 事件PASS条件
        this.passCondition = 0;
        // 处于哪个位面 0：光明；1：黑暗
        this.plane = 0; 
        // 位面切换的CD
        this.planeSwitchCD = 0;
        // 退出双击有效计时
        this.doubleBackTime = 0;
        // 节点动画组件
        this.anim = this.getComponent(cc.Animation);
        // 放置主角预制体
        var actorNode = cc.instantiate(this.actorPerfab);
        this.levelContent.addChild(actorNode);
        actorNode.position = this.startPosition;
        this.actor = actorNode.getComponent("HeroControl");
        this.actor.manager = this;
        actorNode.active = true;
        this.cameraControl.target = actorNode;
        // 放置闪烁预制体
        var scene = cc.director.getScene();
        var flash = cc.instantiate(this.flashPerfab);
        flash.parent = scene;
        this.flashAnim = flash.getComponent(cc.Animation);
        this.guideEvents = [];
        this.onPhone = isMobile;
        // [手机版]获取手柄，并绑定退出事件
        if (this.onPhone) {     
            this.operationNode = cc.instantiate(this.operationBoard);
            this.operationNode.parent = scene;
            this.operationNode.width = this.node.width;
            this.leftButton = this.operationNode.getChildByName('向左');
            this.rightButton = this.operationNode.getChildByName('向右');
            this.jumpButton = this.operationNode.getChildByName('跳跃');
            this.switchButton = this.operationNode.getChildByName('切换');
            // 绑定跳跃事件
            if (this.jumpButton) {
                this.jumpButton.on(cc.Node.EventType.TOUCH_START, event => {
                    this.actorJump();
                }, this);
            };
            // 绑定切换事件
            if (this.switchButton) {
                this.switchButton.on(cc.Node.EventType.TOUCH_START, event => {
                    this.switchPlane();
                }, this);
            };
            // 绑定左右移动事件
            if (this.leftButton) {
                this.leftButton.on(cc.Node.EventType.TOUCH_START, event => {
                    this._updateMove(MOVE_LEFT, true);
                }, this);
                this.leftButton.on(cc.Node.EventType.TOUCH_MOVE, event => {
                    this.updateDirection(event.getLocationX());
                }, this);
                this.leftButton.on(cc.Node.EventType.TOUCH_END, event => {
                    this._updateMove(MOVE_LEFT, false);
                }, this);
                this.leftButton.on(cc.Node.EventType.TOUCH_CANCEL, event => {
                    this._updateMove(MOVE_LEFT, false);
                }, this);
            }
            if (this.rightButton) {
                this.rightButton.on(cc.Node.EventType.TOUCH_START, event => {
                    this._updateMove(MOVE_RIGHT, true);
                }, this);
                this.rightButton.on(cc.Node.EventType.TOUCH_MOVE, event => {
                    this.updateDirection(event.getLocationX());
                }, this);
                this.rightButton.on(cc.Node.EventType.TOUCH_END, event => {
                    this._updateMove(MOVE_RIGHT, false);
                }, this);
                this.rightButton.on(cc.Node.EventType.TOUCH_CANCEL, event => {
                    this._updateMove(MOVE_RIGHT, false);
                }, this);
            };
            cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onMobileBack, this);
        } else {
            // [电脑版]绑定事件监听
            cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
            cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
        };
        // 事件碰触PASS监听
        this.levelContent.on(cc.Node.EventType.TOUCH_START, function (event) {
            if (this.passCondition === CLICK) this.onPass = true;
            console.log('点击PASS');
        }, this);
        this.onLevelSettings();
        AudioManager.playBgm(this.bgm, 1);
    },

    start () {
        this.lightPlane.active = true;
        this.darkPlane.active = false;
    },

    onKeyDown (event) {
        if (this.canOperate) {
            switch(event.keyCode) {
                case cc.macro.KEY.a:
                case cc.macro.KEY.left:
                    if (!this._left) this._updateMove(MOVE_LEFT, true);
                    break;
                case cc.macro.KEY.d:
                case cc.macro.KEY.right:
                    if (!this._right) this._updateMove(MOVE_RIGHT, true);
                    break;
                case cc.macro.KEY.up:
                case cc.macro.KEY.w:
                    if (!this._up) {
                        this.actor.jump();
                    };
                    this._up = true;
                    break;
                case cc.macro.KEY.space:
                    if (!this._space) {
                        this.switchPlane();
                    };
                    this._space = true;
                    break;
                case cc.macro.KEY.x:
                    if (this.doubleBackTime > 0) {
                        this.backToTitle();
                    } else {
                        this.doubleBackTime = 1;
                        var backNode = cc.instantiate(this.backTip);
                        backNode.parent = this.node;
                        var backAnim = backNode.getComponent(cc.Animation);
                        backAnim.finishAnim = function () {
                            this.node.destroy();
                            
                        };
                    }
                    break;
            }
        }
    },

    onMobileBack (event) {
        switch(event.keyCode) {
            case cc.macro.KEY.back:
                if (this.doubleBackTime > 0) {
                    this.backToTitle();
                    if (this.onPhone) cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, this.onMobileBack, this);
                } else {
                    this.doubleBackTime = 1;
                    var backNode = cc.instantiate(this.backTip);
                    backNode.parent = this.node;
                    var backAnim = backNode.getComponent(cc.Animation);
                    backAnim.finishAnim = function () {
                        this.node.destroy();
                    };
                }
                break;
        }
    },

    onKeyUp (event) {
        if (this.canOperate) {
            switch(event.keyCode) {
                case cc.macro.KEY.a:
                case cc.macro.KEY.left:
                    if (this._left) this._updateMove(MOVE_LEFT, false);
                    break;
                case cc.macro.KEY.d:
                case cc.macro.KEY.right:
                    if (this._right) this._updateMove(MOVE_RIGHT, false);
                    break;
                case cc.macro.KEY.up:
                case cc.macro.KEY.w:
                    this._up = false;
                    break;
                case cc.macro.KEY.space:
                    this._space = false;
                    break;
            }
        }
    },

    backToTitle () {
        SceneManager.loadScene('Title');
    },
    // called every frame, uncomment this function to activate update callback
    update: function (dt) {
        if (this.onEvent) {
            this.updateEvent(dt);
        };
        if (this.canOperate) {
            this.updateOperation(dt);
        };
        if (this.doubleBackTime > 0) {
            this.doubleBackTime -= dt;
            if (this.doubleBackTime < 0) this.doubleBackTime = 0;
        }
    },

    // 切换位面操作
    switchPlane () {
        if (this.planeSwitchCD <= 0) {
            // 主角动画
            /*if (this.plane === 0) {
                this.lightPlaneFlash();
            } else {
                this.darkPlaneFlash();
            }*/
            // 播放音效
            AudioManager.playSe('穿越', 0.9);
            var particle = cc.instantiate(this.animParticles[this.plane]);
            particle.position = this.actor.node.position.clone();
            this.levelContent.addChild(particle);
            // 没有与另一位面监视碰撞箱的情况
            let result = this.actor.canSwitchPlane();
            if (result) {
                // 事件PASS条件为切换，且切换成功
                if (this.passCondition === SHIFT) this.onPass = true;
                if (this.plane === 0) {
                    // 切换到暗影位面
                    this.switchDarkPlane();
                } else {
                    // 切换到光明位面
                    this.switchLightPlane();
                }
                
            };
            this.planeSwitchCD = 0.8;
        }
    },
    
    // 切换到光明位面
    switchLightPlane () {
        // 位面节点切换
        this.lightPlane.active = true;
        this.darkPlane.active = false;
        // 主角图像切换
        this.actor.switchLightPlane();
        // 闪烁
        this.flashAnim.play('flash_light');
        this.plane = 0;
        // 若存在切换明面的回调函数则调用它
        if (this.switchLightCallback) {
            this.switchLightCallback();
        };
    },
    
    // 切换到暗影位面
    switchDarkPlane () {
        // 位面节点切换
        this.lightPlane.active = false;
        this.darkPlane.active = true;
        // 主角图像切换
        this.actor.switchDarkPlane();
        // 闪烁
        this.flashAnim.play('flash_dark');
        this.plane = 1;
        // 若存在切换暗面的回调函数则调用它
        if (this.switchDarkCallback) {
            this.switchDarkCallback();
        };
    },

    // 刷新操作
    updateOperation (dt) {
        var speed = this.actor.body.linearVelocity;
        // 左右移动，对应方向加速
        if(this._left) {
            // this.anim.play('walk');
            speed.x -= this.actor.acceleration * dt;
            if (speed.x < -this.actor.maxSpeed) {
                speed.x = -this.actor.maxSpeed;
            } else {
                if (this.actor.particles[2].scaleX > 0) this.actor.switchDirection();
            }
        } 
        else if (this._right) {
            // this.anim.play('walk');
            speed.x += this.actor.acceleration * dt;
            if(speed.x > this.actor.maxSpeed) {
                speed.x = this.actor.maxSpeed;
            } else {
                if (this.actor.particles[2].scaleX < 0) this.actor.switchDirection();
            }
        }  
        else {
            // 不移动时减速
            if (speed.x != 0) {
                var d = this.actor.drag * dt;
                if(Math.abs(speed.x) <= d) {
                    speed.x = 0;
                    // this.anim.play('idle');
                } else {
                    speed.x -= speed.x > 0 ? d : -d;
                }
            }
        }
        if (Math.abs(speed.y) > 1 && this.actor.locatePoint.node.active) this.actor.locatePoint.node.active = false;
        if (this.planeSwitchCD > 0) this.planeSwitchCD -= dt;
        this.actor.body.linearVelocity = speed;
        // 主角越界死亡
        if (this.actor.node.y < this.cameraControl.bottomBound || this.actor.node.x < this.cameraControl.leftBound || this.actor.node.x > this.cameraControl.rightBound) this.gameOver();
    },

    // 刷新事件
    updateEvent (dt) {
        if (this.onPass || this.eventStep === -1) {
            this.processEventEnd();
            // 有事件PASS,或第一个事件都未执行
            if (!this.processNextEvent()) {
                // 下个事件不存在，
                this.onEvent = false;
                this.allowOperation();
                // 若存在关卡正式开始的回调函数则调用它
                if (this.onStartCallback) {
                    this.onStartCallback();
                };
                console.log('所有事件结束');
            };
        };

    },

    // 执行事件
    processNextEvent() {     
        this.onPass = false;
        if (this.eventStep + 1 < this.guideEvents.length) {
            // 如果下一事件存在
            this.eventStep += 1;
            switch (this.guideEvents[this.eventStep].type) {
                case MESSAGE:
                    this.eventNode = cc.instantiate(this.messagePerfab);
                    this.eventNode.parent = this.actor.node;
                    var messageBoardCom = this.eventNode.getComponent(messageBoard);
                    messageBoardCom.setMassage(this.guideEvents[this.eventStep].string);
                    this.forbidOperation();
                    break;
                case TIP:
                    var scene = cc.director.getScene();
                    this.eventNode = cc.instantiate(this.tipLabel);
                    this.eventNode.parent = scene;
                    var label = this.eventNode.getComponent(cc.RichText);
                    label.string =  '<outline color=black width=2>'+this.guideEvents[this.eventStep].string+'</outline>';
                    break;
                default:
                    break;
            };
            this.passCondition = this.guideEvents[this.eventStep].pass;
            console.log('开始事件：'+this.eventStep+'  '+this.passCondition);
            return true;
        } else {
            return false;
        }
    },

    // 结束事件
    processEventEnd() {
        if (this.eventStep === -1) return;
        switch (this.guideEvents[this.eventStep].type) {
            case MESSAGE:
            case TIP:
                this.eventNode.destroy();
                break;
            default:
                break;
        }
        this.allowOperation();
        console.log('结束事件：'+this.eventStep);
    },

    // 按下/抬起移动按键
    _updateMove(direction, mode) {
        if (mode) {
            switch (direction) {
                case MOVE_LEFT:
                    this._left = true;
                    break;
                case MOVE_RIGHT:
                    this._right = true;
                    break;
                default:
                    break;
            }
        } else {
            if (this.onPhone) {
                this.stopMove();
            } else {
                switch (direction) {
                    case MOVE_LEFT:
                        this._left = false;
                        break;
                    case MOVE_RIGHT:
                        this._right = false;
                        break;
                    default:
                        break;
                }
            }
        }
    },

    stopMove() {
        this._left = false;
        this._right = false;
    },

    // [手机版]手柄移动方向
    updateDirection(x) {
        if (x >= (this.leftButton.x + this.rightButton.x + this.node.width) / 2) {
            if (this._left) {
                this._left = false;
                this._updateMove(MOVE_RIGHT,true);
            };
        } else if (this._right) {
            this._right = false;
            this._updateMove(MOVE_LEFT,true);
        }
        
    },

    // 跳跃操作
    actorJump() {
        this.actor.jump();
    },

    // 禁止操作
    forbidOperation () {
        this.canOperate = false;
        this.stopMove();
        if (this.onPhone) this.operationNode.active = false;
    },
    
    // 允许操作
    allowOperation () {
        this.canOperate = true;
        if (this.onPhone) this.operationNode.active = true;
    },

    // 过关
    levelPass() {
        this.forbidOperation();
        if (this.onPhone) cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, this.onMobileBack, this);
        // 若存在过关的回调函数则调用它
        if (this.levelPassCallback) {
            this.levelPassCallback();
        };
        this.actor.body.linearVelocity = cc.Vec2(0, 0);
        this.actor.body.gravityScale = 0;
        var levelPassed = Number(cc.sys.localStorage.getItem('level'));
        if (levelPassed < this.level) levelPassed += 1;
        cc.sys.localStorage.setItem('level', levelPassed);
        AudioManager.playSe('成功', 1);
        var scene = cc.director.getScene();
        var node = cc.instantiate(this.levelPassPerfab);
        node.parent = scene;
    },

    // 死亡
    gameOver() {
        if (!this.gameEnd) {
            this.gameEnd = true;
            this.forbidOperation();
            if (this.onPhone) cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, this.onMobileBack, this);
            // 若存在游戏失败的回调函数则调用它
            if (this.gameOverCallback) {
                this.gameOverCallback();
            };
            this.actor.die();
            var node = cc.instantiate(this.ghost);
            node.parent = this.actor.node;
            node.passPerfab = this.levelPassPerfab;
            var gameoverAnim = node.getComponent(cc.Animation);
            gameoverAnim.callFailure = function () {
                var scene = cc.director.getScene();
                var node = cc.instantiate(this.node.passPerfab);
                AudioManager.playSe('失败', 1);
                var levelOver = node.getChildByName('成功过关').getComponent(LevelPass);
                levelOver.onFail();
                node.parent = scene;
            };
        };
    },
    
    // 在进入关卡时 的设置
    onLevelSettings () {     
        var levelPassed = cc.sys.localStorage.getItem('level');
        if (levelPassed < this.level) {
            // 还未过此关的情况下
            switch (this.level) {
                case 1:
                    this.guideEvents[0] = {
                        type: MESSAGE,
                        string: '这里就是位面神殿的迷宫了，看看附近有没有通路吧',
                        pass: CLICK,
                    };
                    this.guideEvents[1] = {
                        type: TIP,
                        string: (this.onPhone) ? '按下<img src="方向手柄" /><img src="方向手柄-右" />左右移动，按下<img src="跳跃" />跳跃' : '按下左右方向键左右移动，按下上方向键跳跃',
                        pass: 5,
                    };
                    this.guideEvents[2] = {
                        type: MESSAGE,
                        string: '没有通路了？看来，通路在黑暗位面',
                        pass: CLICK,
                    };
                    this.guideEvents[3] = {
                        type: TIP,
                        string: (this.onPhone) ? '按下<img src="切换" />穿越到另一位面对应位置\n另一位面对应位置若有障碍则无法切换哦' : '按下空格键穿越到另一位面对应位置\n另一位面对应位置若有障碍则无法切换哦',
                        pass: SHIFT,
                    };
                    this.guideEvents[4] = {
                        type: MESSAGE,
                        string: '继续寻找出口的通路吧',
                        pass: CLICK,
                    };
                    break;
                case 2:
                    this.guideEvents[0] = {
                        type: MESSAGE,
                        string: '据说，法阵的秘密，藏于三颗原石之中',
                        pass: CLICK,
                    };
                    this.guideEvents[1] = {
                        type: MESSAGE,
                        string: '而三颗原石，在机巧解开时就会出现',
                        pass: CLICK,
                    }; 
                    this.guideEvents[2] = {
                        type: TIP,
                        string: '解开大殿中的机关，收集原石，放置正确位置激活法阵',
                        pass: SHIFT,
                    };
                    break;
                case 3:
                    this.guideEvents[0] = {
                        type: MESSAGE,
                        string: '看来现在已经身处绝境',
                        pass: CLICK,
                    };
                    this.guideEvents[1] = {
                        type: MESSAGE,
                        string: '但我坚信，一定有路能逃出这里！',
                        pass: CLICK,
                    }; 
                    break;
                default:
                    break;
            }
        }
    },
});
